﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Common.Exceptional
{
    public class ManagedException : Exception
    {
        public ManagedException(string message, string code,
            ExceptionLevel level, Exception innerException)
            : base(message, innerException)
        {
            Code = code;
            Level = level;
            AdditoinanlInfos = new Dictionary<string, string>();
        }

        public ManagedException(string message, string code,
            ExceptionLevel level) : base(message)
        {
            Code = code;
            Level = level;
            AdditoinanlInfos = new Dictionary<string, string>();
        }

        public ManagedException(string message, string code = null)
            : this(message, code, ExceptionLevel.Undefined)
        {
            AdditoinanlInfos = new Dictionary<string, string>();

        }

        public string Code { get; private set; }

        public ExceptionLevel Level { get; private set; }

        [Obsolete("废弃这个属性，改用基于Exception.Data的扩展")]
        public Dictionary<string, string> AdditoinanlInfos { get; protected set; }

        protected const string InfoPrefix = "_managed_exception_info_";

        /// <summary>
        /// 从该异常的Data属性中加载符合 InfoPrefix 前缀的数据
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> LoadInfos()
        {
            var result = new Dictionary<string, string>();
            Exception exception = this;
            while (exception != null)
            {
                var temp = exception;
                var keys = exception.Data.Keys.OfType<string>().Where(i => i.StartsWith(InfoPrefix));
                keys.Foreach(k => result.Add(k.Substring(InfoPrefix.Length), temp.Data[k].IfNotNull(i => i.ToString())));
                exception = exception.InnerException;
            }
            return result;
        }

        /// <summary>
        /// 附加信息到异常实例
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="path"></param>
        public void AppendInfo(string key, string value, string path = null)
        {
            if (key.IsNullOrWhiteSpace())
                return;
            var fullKey = path.IsNullOrWhiteSpace()
                ? $"{InfoPrefix}{key}"
                : $"{InfoPrefix}{path}.{key}";
                
            Data[fullKey] = value;
        }
    }
}